﻿namespace ReplayDataFile
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.CompilerServices;

    public class DataRecord
    {
        private byte[] dataBuffer;
        private byte[] zeroLenBuffer;
        private byte ZipFlag;

        public DataRecord()
        {
            this.zeroLenBuffer = new byte[0];
            this.RecType = DataRecordType.FullDataRecord;
            this.IsInterpolationRecord = false;
        }

        public DataRecord(DataRecord rec)
        {
            this.zeroLenBuffer = new byte[0];
            this.DataType = rec.DataType;
            this.DataVersion = rec.DataVersion;
            this.DataBuffer = rec.DataBuffer;
            this.Time = rec.Time;
            this.ZipFlag = rec.ZipFlag;
            this.RecType = rec.RecType;
            this.RecordNo = rec.RecordNo;
            this.IsInterpolationRecord = rec.IsInterpolationRecord;
        }

        public DataRecord(int dataType, byte[] buf, DateTime time)
        {
            this.zeroLenBuffer = new byte[0];
            this.DataType = dataType;
            this.RecType = DataRecordType.FullDataRecord;
            this.DataBuffer = buf;
            this.Time = time;
            this.IsInterpolationRecord = false;
        }

        public bool CanCompactHeader(DataRecord preRecord)
        {
            if (preRecord == null)
            {
                return false;
            }
            if (this.DataBuffer.Length > 0xffff)
            {
                return false;
            }
            long num = this.RecordNo - preRecord.RecordNo;
            if (num > 0xffffL)
            {
                return false;
            }
            TimeSpan span = (TimeSpan) (this.Time - preRecord.Time);
            int totalMilliseconds = (int) span.TotalMilliseconds;
            if ((totalMilliseconds > 0x7fff) || (totalMilliseconds < -32768))
            {
                return false;
            }
            return true;
        }

        public bool FromByteBuffer(BinaryReader br, byte[] buf, DataRecord preRecord)
        {
            int num4;
            if ((buf == null) || (buf.Length == 0))
            {
                return false;
            }
            int position = (int) br.BaseStream.Position;
            this.RecType = (DataRecordType) br.ReadByte();
            this.ZipFlag = br.ReadByte();
            ushort num2 = br.ReadUInt16();
            bool flag = (this.ZipFlag & 0x80) != 0;
            this.ZipFlag = (byte) (this.ZipFlag & 0x7f);
            int num3 = 0;
            if (flag)
            {
                if (preRecord == null)
                {
                    return false;
                }
                num4 = br.ReadUInt16();
                this.RecordNo = preRecord.RecordNo + br.ReadUInt16();
                this.Time = preRecord.Time.AddMilliseconds((double) br.ReadInt16());
                this.DataBuffer = br.ReadBytes(num4);
                num3 = num4 + CompactHeadLength;
            }
            else
            {
                num4 = br.ReadInt32();
                this.RecordNo = br.ReadInt64();
                long ticks = br.ReadInt64();
                this.Time = new DateTime(ticks);
                this.DataBuffer = br.ReadBytes(num4);
                num3 = num4 + HeadLength;
            }
            if (CRC16.CalcCRC16(buf, position + 4, num3 - 4) != num2)
            {
                return false;
            }
            return true;
        }

        public int GetHeadLenght()
        {
            if ((this.ZipFlag & 0x80) != 0)
            {
                return CompactHeadLength;
            }
            return HeadLength;
        }

        public static bool IsDataRecordType(DataRecordType recType)
        {
            switch (recType)
            {
                case DataRecordType.FullDataRecord:
                case DataRecordType.ChangeDataRecord:
                    return true;
            }
            return false;
        }

        public byte[] ToByteBuffer(bool isCompactHead, DataRecord preRecord)
        {
            byte[] buffer = null;
            BinaryWriter writer = null;
            if (isCompactHead && (preRecord != null))
            {
                Debug.Assert(this.DataType == preRecord.DataType);
                Debug.Assert(this.RecordNo > preRecord.RecordNo);
                int num = CompactHeadLength + ((this.DataBuffer == null) ? 0 : this.DataBuffer.Length);
                buffer = new byte[num];
                writer = new BinaryWriter(new MemoryStream(buffer));
                writer.Write((byte) this.RecType);
                this.ZipFlag = (byte) (this.ZipFlag | 0x80);
                writer.Write(this.ZipFlag);
                writer.Write((ushort) 0);
                writer.Write((ushort) this.DataBuffer.Length);
                ushort num2 = (ushort) (this.RecordNo - preRecord.RecordNo);
                writer.Write(num2);
                TimeSpan span = (TimeSpan) (this.Time - preRecord.Time);
                writer.Write((short) span.TotalMilliseconds);
                writer.Write(this.DataBuffer);
            }
            else
            {
                buffer = new byte[this.Size];
                writer = new BinaryWriter(new MemoryStream(buffer));
                writer.Write((byte) this.RecType);
                writer.Write(this.ZipFlag);
                writer.Write((ushort) 0);
                writer.Write((this.DataBuffer == null) ? 0 : this.DataBuffer.Length);
                writer.Write(this.RecordNo);
                writer.Write(this.Time.Ticks);
                if (this.DataBuffer != null)
                {
                    writer.Write(this.DataBuffer);
                }
            }
            ushort num3 = CRC16.CalcCRC16(buffer, 4, buffer.Length - 4);
            writer.Seek(2, SeekOrigin.Begin);
            writer.Write(num3);
            return buffer;
        }

        public override string ToString()
        {
            return string.Format("{0}  {1}  0X{2:X}  RecordNo: {3}  dataLen:{4}", new object[] { this.Time, this.RecType, this.DataType, this.RecordNo, (this.DataBuffer == null) ? 0 : this.DataBuffer.Length });
        }

        public static int CompactHeadLength
        {
            get
            {
                return 10;
            }
        }

        public byte[] DataBuffer
        {
            get
            {
                return ((this.dataBuffer == null) ? this.zeroLenBuffer : this.dataBuffer);
            }
            set
            {
                this.dataBuffer = value;
            }
        }

        public int DataType { get; set; }

        public short DataVersion { get; set; }

        public static int HeadLength
        {
            get
            {
                return 0x18;
            }
        }

        public bool IsInterpolationRecord { get; internal set; }

        public ushort MajorDataType
        {
            get
            {
                return (ushort) (this.DataType >> 0x10);
            }
        }

        public ushort MinorDataType
        {
            get
            {
                return (ushort) (this.DataType & 0xffff);
            }
        }

        public long RecordNo { get; set; }

        public DataRecordType RecType { get; set; }

        public int Size
        {
            get
            {
                if ((this.ZipFlag & 0x80) != 0)
                {
                    return (CompactHeadLength + ((this.DataBuffer == null) ? 0 : this.DataBuffer.Length));
                }
                return (HeadLength + ((this.DataBuffer == null) ? 0 : this.DataBuffer.Length));
            }
        }

        public DateTime Time { get; set; }

        public byte ZipType
        {
            get
            {
                return (byte) (this.ZipFlag & 0x7f);
            }
            set
            {
                this.ZipFlag = (byte) (this.ZipFlag & 0x80);
                this.ZipFlag = (byte) (this.ZipFlag | ((byte) (value & 0x7f)));
            }
        }
    }
}

